package com.beta.auth.utils;

import com.alibaba.cloudapi.sdk.client.ApacheHttpClient;
import com.alibaba.cloudapi.sdk.constant.SdkConstant;
import com.alibaba.cloudapi.sdk.enums.HttpMethod;
import com.alibaba.cloudapi.sdk.enums.ParamPosition;
import com.alibaba.cloudapi.sdk.enums.Scheme;
import com.alibaba.cloudapi.sdk.model.ApiRequest;
import com.alibaba.cloudapi.sdk.model.ApiResponse;
import com.alibaba.cloudapi.sdk.model.HttpClientBuilderParams;
import com.alibaba.fastjson.JSON;
import com.beta.auth.dto.saas.SaaSResponse;
import com.beta.cat.utils.GJsonUtil;
import com.beta.elephant.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;

@RefreshScope
@Slf4j
@Component
public class SaaSApiUtil extends ApacheHttpClient implements InitializingBean, ApplicationListener<EnvironmentChangeEvent> {
    /**
     * 调用saas域名地址
     */
    @Value("${ali.host:}")
    private String aliHost;

    /**
     * 调用saas的appKey
     */
    @Value("${ali.app_key:}")
    private String aliAppKey;

    /**
     * 调用调用saas的appSecret
     */
    @Value("${ali.app_secret:}")
    private String aliAppSecret;

    private static final SaaSApiUtil API_UTIL = new SaaSApiUtil();

    public static SaaSApiUtil getInstance() {
        return API_UTIL;
    }


    @Override
    public void init(HttpClientBuilderParams httpClientBuilderParams) {
        super.init(httpClientBuilderParams);
    }

    /**
     * SaaS接口请求方法（统一方法）
     *
     * @param httpMethod
     * @param path
     * @return
     */
    public static SaaSResponse requestSaaSApi(HttpMethod httpMethod, String path) {
        return requestSaaSApi(httpMethod, path, null, null);
    }

    public static SaaSResponse requestSaaSApi(HttpMethod httpMethod, String path, Map<String, String> queryParam) {
        return requestSaaSApi(httpMethod, path, queryParam, null);
    }

    /**
     * SaaS接口请求方法（统一方法）
     *
     * @param httpMethod
     * @param path
     * @param body
     * @return
     */
    public static SaaSResponse requestSaaSApi(HttpMethod httpMethod, String path, Map<String, String> queryParam, byte[] body) {
        log.info("Request to path:{} , HttpMethod:{}", path, httpMethod.name());

        try {
            ApiRequest request;
            if (body != null) {
                log.info("request body：{}", new String(body));
                request = new ApiRequest(httpMethod, path, body);
            } else {
                request = new ApiRequest(httpMethod, path);
            }
            request.addParam("Content-Type", "application/json; charset=utf-8;", ParamPosition.HEAD, false);
            if (queryParam != null && !queryParam.isEmpty()) {
                log.info("query param:{}", GJsonUtil.toJson(queryParam));
                final Set<Map.Entry<String, String>> entries = queryParam.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    request.addParam(entry.getKey(), entry.getValue(), ParamPosition.QUERY, false);
                }
            }

            final ApiResponse response = getInstance().sendSyncRequest(request);
            doWriteResponseLog(path, response);

            return buildSaaSResponse(response);
        } catch (Exception e) {
            log.error("请求SaaS接口异常，path:{}, queryParam:{}", path, GJsonUtil.toJson(queryParam), e);
            return buildSaaSResponse(null);
        }
    }

    private static SaaSResponse buildSaaSResponse(ApiResponse response) {
        SaaSResponse sResponse = new SaaSResponse();
        if (isSuccess(response)) {
            String apiBody = new String(response.getBody(), SdkConstant.CLOUDAPI_ENCODING);
            sResponse.setSuccess(true);
            sResponse.setResponseBody(apiBody);
            final String errorCode = JSON.parseObject(sResponse.getResponseBody()).getString("ErrorCode");
            if (!"0000".equals(errorCode)) {
                sResponse.setSuccess(false);
            }

            return sResponse;
        }

        return sResponse.setSuccess(false);
    }


    private static void doWriteResponseLog(String path, ApiResponse response) {
        StringBuilder responseLog = new StringBuilder();
        responseLog.append("requestPath:").append(path).append(", Response from backend server").append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF);
        responseLog.append("ResultCode:").append(SdkConstant.CLOUDAPI_LF).append(response.getCode()).append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF);
        if (response.getCode() != 200) {
            responseLog.append("Error description:").append(response.getHeaders().get("X-Ca-Error-Message")).append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF);
        }

        responseLog.append("ResultBody:").append(SdkConstant.CLOUDAPI_LF).append(new String(response.getBody(), SdkConstant.CLOUDAPI_ENCODING));
        log.info(responseLog.toString());
    }

    private static boolean isSuccess(ApiResponse response) {
        return response != null && response.getCode() == ResultVO.success().getCode();
    }

    private void load() {
        HttpClientBuilderParams httpParam = new HttpClientBuilderParams();
        httpParam.setAppKey(aliAppKey);
        httpParam.setAppSecret(aliAppSecret);
        httpParam.setScheme(Scheme.HTTP);
        httpParam.setHost(aliHost);
        API_UTIL.init(httpParam);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        load();
    }

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        final Set<String> changedKeys = event.getKeys();

        if (changedKeys.contains("ali.host") ||
                changedKeys.contains("ali.app_key") ||
                changedKeys.contains("ali.app_secret")) {
            load();
        }
    }
}
